import { Body, Controller, Get, Post, Query, Req, Res } from '@nestjs/common';
import { JsapiOrder, RefundByOutTradeNoOptions, WechatService } from 'nest-wxpay';
import { Request } from 'express';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { OrderService } from '../order/order.service';
import { InfoService } from '../info/info.service';
import { NotRequireAuth } from '../user/user.decorator';
import { readFileSync } from 'fs';
import { join } from 'path';
import { createSign } from 'crypto';

// 定义微信支付回调解密后的数据结构
interface WechatPayCallbackData {
  transaction_id: string; // 微信支付订单号
  out_trade_no: string; // 商户订单号
  trade_state: string; // 交易状态
  trade_state_desc: string; // 交易状态描述
  success_time: string; // 支付成功时间
  payer: {
    openid: string; // 用户标识
  };
  amount: {
    total: number; // 总金额
    payer_total: number; // 用户支付金额
    currency: string; // 货币类型
    payer_currency: string; // 用户支付币种
  };
  // 其他可能的字段...
  [key: string]: any;
}

@ApiTags('微信支付')
@Controller('system/pay')
@ApiBearerAuth('Authorization')
export class PayController {
  constructor(
    private readonly wechatService: WechatService,
    private readonly orderService: OrderService,
    private readonly infoService: InfoService,
  ) {}

  /**
   * 创建支付订单（供小程序调用）
   */
  @ApiOperation({
    summary: '创建支付订单（供小程序调用）',
  })
  @Post('jsapi/create')
  async createJsapiOrder(
    @Body()
    orderData: {
      parentId: number;
      childId: number;
      out_trade_no: string; // 商户订单号（需唯一，如20240520123456789）
      total: number; // 订单金额（单位：分，如100=1元）
      description: string; // 订单描述（如"商品购买"）
      openid: string; // 用户openid（公众号/小程序授权获取）
      notify_url: string; // 支付回调地址（需公网可访问，且与商户平台配置一致）
    },
  ) {
    orderData.total = 990;
    // 获取openid
    orderData.openid = await this.infoService.getOpenid(orderData.parentId);

    // 生成商户订单号：时间(年月日小时分钟秒) + 用户id
    const date = new Date();
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始，补0
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    // 拼接时间字符串（例如：20240925143025）
    const timeStr = `${year}${month}${day}${hours}${minutes}${seconds}`;
    orderData.out_trade_no = `${timeStr}${orderData.childId}`;
    orderData.notify_url = 'https://www.zyhxai.com/api/system/pay/wechat/notify';

    // 构造JSAPI下单参数（符合JsapiOrder类型）
    const jsapiOrder: JsapiOrder = {
      out_trade_no: orderData.out_trade_no,
      amount: {
        total: orderData.total, // total应该在amount对象内
      },
      description: orderData.description,
      payer: { openid: orderData.openid }, // JSAPI必须传payer.openid
      notify_url: orderData.notify_url, // 支付结果回调地址
    };

    // 调用WechatService创建JSAPI订单
    const result = await this.wechatService.createJsapiOrder(jsapiOrder);

    const order = await this.orderService.create({
      orderNo: orderData.out_trade_no,
      userId: orderData.childId,
      totalAmount: orderData.total,
      productName: orderData.description,
      productDesc: orderData.description,
      payType: 1,
      orderStatus: 0,
      payAmount: orderData.total,
    });

    // 生成微信支付所需参数（V3版本签名）
    const timeStamp = Math.floor(Date.now() / 1000).toString();
    const nonceStr = this.generateNonceStr();
    const packageStr = `prepay_id=${result.prepay_id}`;
    const signType = 'RSA'; // V3版本使用RSA签名

    // 生成支付签名（V3版本签名规则）
    const paySign = this.generateV3PaySign({
      appId: 'wx862971d956a0aeaf',
      timeStamp,
      nonceStr,
      package: packageStr,
    });

    // 返回结果给前端（前端需用result.prepay_id调起微信支付）
    return {
      code: 200,
      message: 'JSAPI订单创建成功',
      data: {
        timeStamp,
        nonceStr,
        package: packageStr,
        signType,
        paySign,
      },
    };
  }

  /**
   * 生成随机字符串
   */
  private generateNonceStr(length: number = 32): string {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let nonceStr = '';
    for (let i = 0; i < length; i++) {
      nonceStr += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return nonceStr;
  }

  /**
   * 生成V3版本支付签名
   */
  private generateV3PaySign(params: { appId: string; timeStamp: string; nonceStr: string; package: string }): string {
    const message = `${params.appId}\n${params.timeStamp}\n${params.nonceStr}\n${params.package}\n`;

    // 从环境变量或配置中获取私钥，而不是硬编码
    const privateKey = readFileSync(join(__dirname, 'apiclient_key.pem'), 'utf8');

    try {
      const sign = createSign('RSA-SHA256');
      sign.update(message);
      return sign.sign(privateKey, 'base64');
    } catch (error) {
      console.error('签名生成失败:', error);
      throw new Error('支付签名生成失败');
    }
  }

  /**
   * 回调接口实现（如/payment/wechat/notify）
   */
  @ApiOperation({
    summary: '回调接口实现',
  })
  @Post('wechat/notify')
  @NotRequireAuth()
  async handleWechatNotify(@Req() req: Request, @Res() res: Response) {
    try {
      // 1. 获取微信回调的头部参数（用于签名验证）
      const timestamp = req.headers['wechatpay-timestamp'] as string;
      const nonce_str = req.headers['wechatpay-nonce'] as string;
      const signature = req.headers['wechatpay-signature'] as string;
      const serial_no = req.headers['wechatpay-serial'] as string;

      // 验证必要的头部参数
      if (!timestamp || !nonce_str || !signature || !serial_no) {
        throw new Error('缺少微信支付回调必要的头部参数');
      }

      // 2. 获取回调的请求体（raw格式，需保留原始JSON字符串）
      const requestBody = JSON.stringify(req.body);

      // // 3. 验证签名（确保回调来自微信，未被篡改）
      // const verifyResult = await this.wechatService.verifySign({
      //   timestamp: +timestamp,
      //   nonce_str,
      //   requestBody,
      //   signature,
      // });
      // if (!verifyResult) {
      //   throw new Error('签名验证失败');
      // }

      // 4. 解密回调中的加密数据（支付结果在req.body.resource中）
      const decryptedData: WechatPayCallbackData = await this.wechatService.decryptPayCallback({
        nonce: req.body.resource.nonce,
        associated_data: req.body.resource.associated_data,
        ciphertext: req.body.resource.ciphertext,
      });

      // 5. 处理支付结果（如更新订单状态为"已支付"）
      // decryptedData包含订单关键信息：out_trade_no（商户订单号）、trade_state（支付状态）等
      console.log('支付回调解密结果：', decryptedData);
      // TODO: 业务逻辑（如更新数据库订单状态、发送通知等）

      // 6. 向微信返回成功响应（必须返回此格式，否则微信会重复回调）
      if (decryptedData.trade_state === 'SUCCESS') {
        //检查订单是否处理过
        const order = await this.orderService.findOneByorderNo(decryptedData.out_trade_no);
        if (order.orderStatus === 0) {
          // 更新订单状态
          const updateResult = await this.orderService.updateOrderStatus(
            decryptedData.out_trade_no, // 商户订单号
            1, // 1表示已支付
            decryptedData.transaction_id, // 微信支付订单号
            new Date(decryptedData.success_time), // 支付成功时间
          );

          if (!updateResult) {
            console.error('更新订单状态失败:', decryptedData.out_trade_no);
          } else {
            // 这里可以添加支付成功后的其他业务逻辑
            // 例如：发送支付成功通知、更新库存、生成电子凭证等
            console.log('订单状态更新成功:', decryptedData.out_trade_no);
            // await this.orderService.

            // 获取用户id 改变会员状态 增加会员结束时间
            const childInfo = await this.orderService.findUserByOrderNo(decryptedData.out_trade_no);

            if (childInfo) {
              if (childInfo.status === '0') {
                // 改变会员状态
                childInfo.status = '1';
                // 根据当时时间增加会员结束时间
                childInfo.endTime = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30);
              } else {
                // 检查会员是否已过期
                const isExpired = !childInfo.endTime || childInfo.endTime <= new Date();
                if (isExpired) {
                  // 如果已过期，从当前时间开始计算
                  childInfo.endTime = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30);
                } else {
                  // 如果未过期，在原有结束时间基础上延长
                  childInfo.endTime = new Date(childInfo.endTime.getTime() + 1000 * 60 * 60 * 24 * 30);
                }
              }
              // 保存更新后的用户信息
              const updateResult = await this.infoService.updateMemberStatus(childInfo.userId, childInfo.endTime);
              if (!updateResult) {
                console.error('更新用户会员状态失败:', childInfo.userId);
              } else {
                console.log('用户会员状态更新成功:', childInfo.userId);
              }
            }
          }
        }
      }
      return {
        code: 'SUCCESS',
        message: '成功',
      };
    } catch (error) {
      console.error('支付回调处理失败：', error);
      // 回调失败时，返回错误响应（微信会重试）
      return {
        code: 'FAIL',
        message: error.message || '处理失败',
      };
    }
  }

  /**
   *  按商户订单号查询订单
   */
  @ApiOperation({
    summary: '按商户订单号查询订单',
  })
  @Get('order/query')
  async queryOrder(@Query('out_trade_no') out_trade_no: string) {
    const order = await this.wechatService.queryOrderByOutTradeNo(out_trade_no);
    return {
      code: 200,
      data: order, // 包含订单状态（trade_state）、支付时间等信息
    };
  }

  /**
   * 关闭未支付订单
   */
  @ApiOperation({
    summary: '关闭未支付订单',
  })
  @Post('order/close')
  async closeOrder(@Body('out_trade_no') out_trade_no: string) {
    await this.wechatService.closeOrder(out_trade_no);
    return {
      code: 200,
      message: '订单已成功关闭',
    };
  }

  /**
   * 通过商户订单号发起退款（需传入退款单号、退款金额等）：
   */
  @ApiOperation({
    summary: '通过商户订单号发起退款（需传入退款单号、退款金额等）：',
  })
  @Post('refund')
  async createRefund(
    @Body()
    refundData: {
      out_trade_no: string; // 原商户订单号
      out_refund_no: string; // 退款单号（需唯一，如REF20240520123456）
      refund: number; // 退款金额（单位：分，需≤原订单金额）
      total: number; // 原订单总金额（单位：分）
      notify_url?: string; // 退款回调地址（可选）
    },
  ) {
    const refundOptions: RefundByOutTradeNoOptions = {
      out_trade_no: refundData.out_trade_no,
      out_refund_no: refundData.out_refund_no,
      amount: {
        refund: refundData.refund,
        total: refundData.total,
        currency: 'CNY', // 货币类型，默认CNY
      },
      notify_url: refundData.notify_url, // 退款结果回调地址（可选）
    };

    const refundResult = await this.wechatService.refundByOutTradeNo(refundOptions);
    return {
      code: 200,
      message: '退款申请已提交',
      data: refundResult, // 包含refund_id（退款单号）、refund_status（退款状态）
    };
  }
}
